/**
* \file		Technologie.c
* \brief	Code des fonctions du module Technologie
* \details	C'est ici qu'est le code des accesseurs, mutateurs ainsi que
*		la fonction de test vérifant le bon fonctionnement du module
*		Technologie.
*		Une description de la structure Terrain est fournie à
*		la rubrique \link Technologie.h
*/

#include "Technologie.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

/*========================== Gestion de la mémoire ==========================*/
void initTech(Technologie *ptech, char *nom, char *descr, int nbPrer, int nbDebloquees)
{
   int i;

   setIDTech(ptech, 0);

   ptech->nom = (char *)malloc((strlen(nom)+1)*sizeof(char));
   strcpy(ptech->nom, nom);

   ptech->descr = (char *)malloc((strlen(descr)+1)*sizeof(char));
   strcpy(ptech->descr, descr);

/* Initialisation des prix */
   setCoutBoisTech(ptech, 0);
   setCoutMetalTech(ptech, 0);
   setCoutBiereTech(ptech, 0);
   setCoutNourritureTech(ptech, 0);

/* Initialisation des bonus */
   setBonusAttaqueTech(ptech, 0);
   setBonusDefenseTech(ptech, 0);
   setBonusFeconditeTech(ptech, 0);
   setBonusMortaliteTech(ptech, 0);
   setBonusImmigrationTech(ptech, 0);
   setBonusEmigrationTech(ptech, 0);
   setBonusMoralTech(ptech, 0);
   setBonusProdTech(ptech, 0);

/* Initialisation des malus */
   setMalusAttaqueTech(ptech, 0);
   setMalusDefenseTech(ptech, 0);
   setMalusFeconditeTech(ptech, 0);
   setMalusMortaliteTech(ptech, 0);
   setMalusImmigrationTech(ptech, 0);
   setMalusEmigrationTech(ptech, 0);
   setMalusMoralTech(ptech, 0);
   setMalusProdTech(ptech, 0);

   setDevTech(ptech, 0);
   setNbPrerequisProdTech(ptech, nbPrer);

/* Tableau des prérequis */
   ptech->tabNec = (Prerequis *)malloc(nbPrer*sizeof(Prerequis));

   for(i=0;i<nbPrer;i++)
	{
	   initPrer(&(ptech->tabNec[i]));
	}

/* Technologie suivante */
   setTechSuivTech(ptech, NULL);

/* Nombre de technologies débloquées */
   setNbTechDebloqueesTech(ptech, nbDebloquees);

/* Tableau des technologies débloquées */
    ptech->tabTechDebloquees = (Technologie **)malloc(nbDebloquees*sizeof(Technologie*));

/* Tableau des ID des technologies débloquées */
    ptech->tabIDTechDebl = (int *)malloc(nbDebloquees*sizeof(int));

    for(i=0; i<nbDebloquees; i++)
    {
        setTabTechDebloqueesTech(ptech, NULL, i);
        setTabIDTechDebloqueesTech(ptech, 0, i);
    }

}

void creerTech(Technologie **nouvTech, char *nom, char *descr, int nbPrer, int nbDebloquees)
{
   *nouvTech = (Technologie *)malloc(sizeof(Technologie));
   initTech(*nouvTech, nom, descr, nbPrer, nbDebloquees);
}

void libereTech(Technologie *ptech)
{
   free(ptech->nom);
   free(ptech->descr);
   free(ptech->tabNec);
   free(ptech->tabTechDebloquees);
   free(ptech->tabIDTechDebl);
}

void detruireTech(Technologie *ptech)
{
   libereTech(ptech);
   free(ptech);
}

/*============================= Accesseurs =============================*/

int getIDTech(const Technologie *ptech)
{
   return ptech->ID;
}

char *getNomTech(const Technologie *ptech)
{
   return ptech->nom;
}

char *getDescriptionTech(const Technologie *ptech)
{
   return ptech->descr;
}

int getCoutBoisTech(const Technologie *ptech)
{
   return ptech->prix[0];
}

int getCoutMetalTech(const Technologie *ptech)
{
   return ptech->prix[1];
}

int getCoutBiereTech(const Technologie *ptech)
{
   return ptech->prix[2];
}

int getCoutNourritureTech(const Technologie *ptech)
{
   return ptech->prix[3];
}

int getBonusAttaqueTech(const Technologie *ptech)
{
   return ptech->bonus[0];
}

int getBonusDefenseTech(const Technologie *ptech)
{
   return ptech->bonus[1];
}

int getBonusFeconditeTech(const Technologie *ptech)
{
   return ptech->bonus[2];
}

int getBonusMortaliteTech(const Technologie *ptech)
{
   return ptech->bonus[3];
}

int getBonusImmigrationTech(const Technologie *ptech)
{
   return ptech->bonus[4];
}

int getBonusEmigrationTech(const Technologie *ptech)
{
   return ptech->bonus[5];
}

int getBonusMoralTech(const Technologie *ptech)
{
   return ptech->bonus[6];
}

int getBonusProdTech(const Technologie *ptech)
{
   return ptech->bonus[7];
}

int getMalusAttaqueTech(const Technologie *ptech)
{
   return ptech->malus[0];
}

int getMalusDefenseTech(const Technologie *ptech)
{
   return ptech->malus[1];
}

int getMalusFeconditeTech(const Technologie *ptech)
{
   return ptech->malus[2];
}

int getMalusMortaliteTech(const Technologie *ptech)
{
   return ptech->malus[3];
}

int getMalusImmigrationTech(const Technologie *ptech)
{
   return ptech->malus[4];
}

int getMalusEmigrationTech(const Technologie *ptech)
{
   return ptech->malus[5];
}

int getMalusMoralTech(const Technologie *ptech)
{
   return ptech->malus[6];
}

int getMalusProdTech(const Technologie *ptech)
{
   return ptech->malus[7];
}

char getDevTech(const Technologie *ptech)
{
   return ptech->dev;
}

int getNbPrerequisProdTech(const Technologie *ptech)
{
   return ptech->nbPrerequis;
}

Prerequis *getTabPrerequisProdTech(const Technologie *ptech)
{
   return ptech->tabNec;
}

Technologie *getTechSuivTech(const Technologie *ptech)
{
   return ptech->techSuiv;
}

int getIDIemePrerequisTech(const Technologie *ptech, int i)
{
   Prerequis *tabPrer;
   int nbPrer = getNbPrerequisProdTech(ptech);
   if(nbPrer == 0)
	{
	   return -1;
	}
   else
	{
	   tabPrer = getTabPrerequisProdTech(ptech);
	   return getIDPrer(&tabPrer[i]);
	}
}

char getDevPrerTech(const Technologie *ptech, int ID)
{
   int i,max;

   max = getNbPrerequisProdTech(ptech);

   for(i=0;i<max;i++)
	{
	   if(ID == ptech->tabNec[i].IDTech)
		{
		   return ptech->tabNec[i].dev;
		}
	}
/* si on est là, c'est que l'ID n'était pas dans le tableau => -1 */
   return -1;
}

Technologie **getTechDebloqueesTech(const Technologie *ptech)
{
    return ptech->tabTechDebloquees;
}

int getNbTechDebloqueesTech(const Technologie *ptech)
{
    return ptech->nbTechDebloquees;
}

Technologie *getIemeTechDebloqueeTech(const Technologie *ptech, int i)
{
   Technologie **tabDeb;
   int nbDeb = getNbTechDebloqueesTech(ptech);
   if(nbDeb == 0)
	{
	   return NULL;
	}
   else
	{
	   tabDeb = getTechDebloqueesTech(ptech);
	   return tabDeb[i];
	}
}

int *getTabIDTechDebloqueeTech(const Technologie *ptech)
{
    return ptech->tabIDTechDebl;
}

int getIemeIDTechDebloqueeTech(const Technologie *ptech, int i)
{
   int *tabDebl;
   int nbDebl = getNbTechDebloqueesTech(ptech);
   if(nbDebl == 0)
	{
	   return -1;
	}
   else
	{
	   tabDebl = getTabIDTechDebloqueeTech(ptech);
	   return tabDebl[i];
	}
}
/*============================== Mutateurs ==============================*/

void setIDTech(Technologie *ptech, int nouvID)
{
   ptech->ID = nouvID;
}

void setNomTech(Technologie *ptech, char *nouvNom)
{
   free(ptech->nom);
   ptech->nom = (char *)malloc((strlen(nouvNom)+1)*sizeof(char));
   strcpy(ptech->nom, nouvNom);
}

void setDescriptionTech(Technologie *ptech, char *nouvDescr)
{
   free(ptech->descr);
   ptech->descr = (char *)malloc((strlen(nouvDescr)+1)*sizeof(char));
   strcpy(ptech->descr, nouvDescr);
}

void setCoutBoisTech(Technologie *ptech, int nouvCout)
{
   ptech->prix[0] = nouvCout;
}

void setCoutMetalTech(Technologie *ptech, int nouvCout)
{
   ptech->prix[1] = nouvCout;
}

void setCoutBiereTech(Technologie *ptech, int nouvCout)
{
   ptech->prix[2] = nouvCout;
}

void setCoutNourritureTech(Technologie *ptech, int nouvCout)
{
   ptech->prix[3] = nouvCout;
}

void setBonusAttaqueTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[0] = nouvBonus;
}

void setBonusDefenseTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[1] = nouvBonus;
}

void setBonusFeconditeTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[2] = nouvBonus;
}

void setBonusMortaliteTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[3] = nouvBonus;
}

void setBonusImmigrationTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[4] = nouvBonus;
}

void setBonusEmigrationTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[5] = nouvBonus;
}

void setBonusMoralTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[6] = nouvBonus;
}

void setBonusProdTech(Technologie *ptech, int nouvBonus)
{
   ptech->bonus[7] = nouvBonus;
}

void setMalusAttaqueTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[0] = nouvMalus;
}

void setMalusDefenseTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[1] = nouvMalus;
}

void setMalusFeconditeTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[2] = nouvMalus;
}

void setMalusMortaliteTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[3] = nouvMalus;
}

void setMalusImmigrationTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[4] = nouvMalus;
}

void setMalusEmigrationTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[5] = nouvMalus;
}

void setMalusMoralTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[6] = nouvMalus;
}

void setMalusProdTech(Technologie *ptech, int nouvMalus)
{
   ptech->malus[7] = nouvMalus;
}

void setDevTech(Technologie *ptech, char nouvVal)
{
   ptech->dev = nouvVal;
}

void setNbPrerequisProdTech(Technologie *ptech, int nouvNb)
{
   ptech->nbPrerequis = nouvNb;
}

void setDevPrerTech(Technologie *ptech, int ID, char nouvVal)
{
   int i,max;

   max = getNbPrerequisProdTech(ptech);

   for(i=0;i<max;i++)
	{
	   if(ID == ptech->tabNec[i].IDTech)
		{
		   setDevPrer(&(ptech->tabNec[i]), nouvVal);
		}
	}

}

void setTabPrerTech(Technologie *ptech, int ID, int numCase)
{
   setIDPrer(&(ptech->tabNec[numCase]), ID);
}

void setTechSuivTech(Technologie *ptech, Technologie *techSuiv)
{
   ptech->techSuiv = techSuiv;
}


void setTabCoutTech(Technologie *ptech, int nouvCout, int numCase)
{
   ptech->prix[numCase] = nouvCout;
}

void setTabBonusTech(Technologie *ptech, int nouvBonus, int numCase)
{
   ptech->bonus[numCase] = nouvBonus;
}

void setTabMalusTech(Technologie *ptech, int nouvMalus, int numCase)
{
   ptech->malus[numCase] = nouvMalus;
}

void setNbTechDebloqueesTech(Technologie *ptech, int nouvNb)
{
    ptech->nbTechDebloquees = nouvNb;
}

void setTabTechDebloqueesTech(Technologie *ptech, Technologie *pnouvLien, int numCase)
{
    ptech->tabTechDebloquees[numCase] = pnouvLien;
}

void setTabIDTechDebloqueesTech(Technologie *ptech, int nouvID, int numCase)
{
    ptech->tabIDTechDebl[numCase] = nouvID;
}

/*========================== Fonctions autres ==========================*/

char devDisponibleTech(Technologie *ptech, Entrepot *pstock)
{
   int i, compte = 0;
   int nbNec = getNbPrerequisProdTech(ptech);
   Prerequis *tabNec = getTabPrerequisProdTech(ptech);
   unsigned int bois, metal, biere, nourriture;

   bois = getBoisEntr(pstock);
   metal = getMetalEntr(pstock);
   biere = getBiereEntr(pstock);
   nourriture = getNourritureEntr(pstock);

   for(i=0; i<nbNec; i++)
	{
	   compte += tabNec[i].dev;
	}
   if(compte != nbNec)
	{
	   return 0;
	}

   else
	   if((getCoutBoisTech(ptech) > bois)
		|| (getCoutMetalTech(ptech) > metal)
		|| (getCoutBiereTech(ptech) > biere)
		|| (getCoutNourritureTech(ptech) > nourriture)
		)
		{
		   return -1;
		}
	   else
		{
		   return 1;
		}
}

int getNumSADepuisIDTech(int ID)
{
   int res;
   res = ID/10000;
   return res - 10;
}

int getNumBrancheDepuisIDTech(int ID)
{
   int res = ID;
   res = res - (10 + getNumSADepuisIDTech(ID))*10000;
   res = res/100;
   return res;
}

int getNumSATech(const Technologie *ptech)
{
   int res;
   res = getIDTech(ptech);
   return getNumSADepuisIDTech(res);
}

int getNumBrancheTech(const Technologie *ptech)
{
   int res = getIDTech(ptech);
   res = getNumBrancheDepuisIDTech(res);
   return res;
}


/*========================== Fonction de Test ==========================*/
/**
* \brief	Procédure interne : teste les Set et les Get du module
* \param	valIni		Entier, valeur initiale
* \param	valRemp		Tableau d'entiers listant les valeurs qui
*				remplaceront successivement les différentes
*				valeurs de la technologie
* \param	tabpGet		Tableau de pointeurs sur fonction
*				récapitulant les Get à tester
* \param	tabpSet		Tableau de pointeurs sur fonction
*				récapitulant les Set à tester
* \param	nbFonc		Nombre de paires Set/Get à tester
* \param	nbVar		Nombre de valeurs à modifier en tout
* \param	tech		Technologie initialisée
*/
static void verifGetSetTech(int valIni,
		 int valRemp[],
		 int (*tabpGet[])(const Technologie *),
		 void (*tabpSet[])(Technologie *, int),
		 int nbFonc,
		 int nbVar,
		 Technologie *tech )
{
   int i, j;

   for(i=0; i<nbFonc; i++)
	{
	   for(j=0; j<nbVar ;j++)
		{
		   tabpSet[i](tech, valRemp[j]);
		   assert(valRemp[j] == tabpGet[i](tech));
		}
	}
}



void testTech()
{
   Technologie *techTest;
   Entrepot stock;
   int i;
   char *nom = "Nom Tech";
   char *descr = "description Tech";
   char texte[][150] = {"test d'un nom très très long pour une tech","essai", ",/\nsj yjnz", "Eléonore", "Texte avec caractères étranges façon tabulations \t et retour à la ligne \n 'ui&izjàsçx"};

   int var[] = {-20, 0, 10, 100, -50, 70};
   int IDtechNec[] = {000000, 000001, 000100};

/* tableau de pointeurs pointant sur les différents Get renvoyant un entier à tester */
   int (*tabpGet[])(const Technologie *) = {
	getIDTech,
	getCoutBoisTech,
	getCoutMetalTech,
	getCoutBiereTech,
	getCoutNourritureTech,
	getBonusAttaqueTech,
	getBonusDefenseTech,
	getBonusFeconditeTech,
	getBonusMortaliteTech,
	getBonusImmigrationTech,
	getBonusEmigrationTech,
	getBonusMoralTech,
	getBonusProdTech,
	getMalusAttaqueTech,
	getMalusDefenseTech,
	getMalusFeconditeTech,
	getMalusMortaliteTech,
	getMalusImmigrationTech,
	getMalusEmigrationTech,
	getMalusMoralTech,
	getMalusProdTech,
	getNbPrerequisProdTech
	};

/* tableau de pointeurs pointant sur les différents set associés */
   void (*tabpSet[])(Technologie *, int) = {
	setIDTech,
	setCoutBoisTech,
	setCoutMetalTech,
	setCoutBiereTech,
	setCoutNourritureTech,
	setBonusAttaqueTech,
	setBonusDefenseTech,
	setBonusFeconditeTech,
	setBonusMortaliteTech,
	setBonusImmigrationTech,
	setBonusEmigrationTech,
	setBonusMoralTech,
	setBonusProdTech,
	setMalusAttaqueTech,
	setMalusDefenseTech,
	setMalusFeconditeTech,
	setMalusMortaliteTech,
	setMalusImmigrationTech,
	setMalusEmigrationTech,
	setMalusMoralTech,
	setMalusProdTech,
	setNbPrerequisProdTech
	};


   printf("Test de Technologie\n");
   printf("\tCréation et initialisation d'une Technologie\t");

   creerTech(&techTest, nom, descr, 5, 5);
   printf("OK\n");

   printf("\tAffectation et récupération de valeurs\t\t");
   verifGetSetTech(0, var, tabpGet, tabpSet, 5, 6, techTest);

   for(i=0; i<5;i++)
	{
	   setNomTech(techTest, texte[i]);
	   assert(0 == strcmp(texte[i], getNomTech(techTest)));
	}

   printf("OK\n");

   printf("\tTest de la possibilité de développer une technologie\t");
   /* Mise en place de l'entrepôt */
   initRessourcesEntr(&stock);

   /* Mise en place de la technologie de test */
   setNbPrerequisProdTech(techTest, 3);
   for(i=0; i<3; i++)
	{
	   setTabPrerTech(techTest, IDtechNec[i], i);
	}

   setCoutBoisTech(techTest, 50);
   setCoutMetalTech(techTest, 50);
   setCoutBiereTech(techTest, 50);
   setCoutNourritureTech(techTest, 50);

/* Les technologies nécessaires n'ont pas été développées */
   for(i=0; i<3; i++)
	{
	   setDevPrerTech(techTest, IDtechNec[i], 0);
	}
   assert(0 == devDisponibleTech(techTest, &stock));

/* Toutes les technologies nécessaires ont été développées, mais les ressources sont insuffisantes */
   for(i=0; i<3; i++)
	{
	   setDevPrerTech(techTest, IDtechNec[i], 1);
	}
   assert(-1 == devDisponibleTech(techTest, &stock));

/* Tous les prérequis sont remplis, les ressources sont en stock */
   ajouteBoisEntr(&stock, 100);
   ajouteMetalEntr(&stock, 100);
   ajouteHoublonEntr(&stock, 100);
   ajouteNourritureEntr(&stock, 100);
   ajouteBiereEntr(&stock, 100);

   assert(1 == devDisponibleTech(techTest, &stock));

/* Les ressources sont en stock mais une des technologies nécessaires manque */
   setDevPrerTech(techTest, IDtechNec[0], 0);
   assert(0 == devDisponibleTech(techTest, &stock));

   printf("OK\n");


   detruireTech(techTest);
}
